/*
 * UiUtil.h
 *
 *  Created on: 2012-10-17
 *      Author: yangentao@gmail.com
 */

#ifndef UIUTIL_H_
#define UIUTIL_H_
#include <winutil/winutil.h>
#include "headers.h"
using namespace std;


class ObjectInuseException: public exception{

};

class Size: public SIZE{
public:
	explicit Size(int cx=0, int cy=0);
	int width();
	int height();
};

class Point: public POINT {
public:
	explicit Point(int x_ = 0, int y_ = 0);

};

class Rect: public RECT {
public:
	Rect(RECT r);
	explicit Rect(int left_ = 0, int top_ = 0, int right_ = 0, int bottom_ = 0);

	bool operator==(Rect& rc);
	bool Contains(Point pt);
	bool Contains(int x, int y);
	bool Contains(Rect& rc);
	bool Intersects(Rect& other);
	void Move(int xDelta, int yDelta);
	void offset(int dx, int dy);
	int Width();
	int Height();
	bool Empty();

	void zoom(int dx, int dy);
	void zoom(int deltaXY);
};

inline Rect Xywh(int x, int y, int w, int h){
	return Rect(x, y, x + w, y + h);
}

class Rgn {
private:
	Rgn(const Rgn&);
	Rgn& operator=(const Rgn&);
public:
	Rgn();
	Rgn(HRGN rgn_);
	Rgn(Rect r);
	Rgn(Rect r, int w, int h);
	virtual ~Rgn();

	void setRgn(HRGN rgn_);
	HRGN getRgn() const;

	operator HRGN();
	void freeRgn();
	void manageRgn(HRGN rgn_);

	bool needFree();
	HRGN discard();

	void grab(Rgn& other);

	void createEmptyRgn();
	void createRectRgn(Rect r);
	void createRectRgn(int left, int top, int right, int bottom);
	void createRoundRectRgn(Rect r, int w, int h);

	Rgn& OR(const Rgn& other);
	Rgn& DIFF(const Rgn& other);
	Rgn& AND(const Rgn& other);

	BOOL Contains(int x, int y);
	BOOL Contains(Point pt);

private:
	HRGN rgn;
	bool owner;
};

/**
 * Holds a desired RGB colour.
 */
class Color {
	UINT32 co;
public:
	Color(UINT32 lcol = 0);

	Color(UINT32 red, UINT32 green, UINT32 blue);
	Color(UINT32 red, UINT32 green, UINT32 blue, UINT32 alpha);

	bool operator==(const Color& other) const;

	operator COLORREF();
	Color& operator =(COLORREF colorref);

	void Set(UINT32 lcol);

	void Set(UINT32 red, UINT32 green, UINT32 blue);
	void Set(UINT32 red, UINT32 green, UINT32 blue, UINT32 alpha);
	static UINT32 ValueOfHex(char ch);

	//TODO support Alpha
	void SetStr(const char* val);

	UINT32 AsLong() const;
	COLORREF toColorRef() const;

	UINT32 GetRed();

	UINT32 GetGreen();

	UINT32 GetBlue();
	UINT32 GetAlpha();
};



struct FontParameters {
	String faceName;
	float size;
	int weight;
	bool italic;
	int extraFontFlag;
	int technology;
	int characterSet;

	FontParameters(const char* faceName_, float size_ = 10, int weight_ = 400, bool italic_ = false, int extraFontFlag_ = 0, int technology_ = 0, int characterSet_ = 0)
			:

			size(size_), weight(weight_), italic(italic_), extraFontFlag(extraFontFlag_), technology(technology_), characterSet(characterSet_) {
		faceName = faceName_;
	}

};

class Font {
protected:
	HFONT fid;

	// Private so Font objects can not be copied
	Font(const Font &);
	Font &operator=(const Font &);
public:
	Font();
	virtual ~Font();

	virtual void Create(const char *faceName, int characterSet, int size, bool bold, bool italic, int extraFontFlag = 0);
	virtual void Release();

	HFONT GetID() {
		return fid;
	}
	// Alias another font - caller guarantees not to Release
	void SetID(HFONT fid_) {
		fid = fid_;
	}

	operator HFONT() {
		return fid;
	}

};

//32bit color
//must assign the first and last color,  colors[0] and colors[length-1]
//length >2
//  [(100,100,255), (x,x,x), (x,x,x), (200, 200, 255)]
//=>[(100,100,255), (133,133,255), (166,166,255), (200, 200, 255)]
void transformColor(DWORD colors[], int length);

COLORREF reverseColorRB(COLORREF color);



//===================================================

inline Size::Size(int cx_, int cy_) {
	cx = cx_;
	cy = cy_;
}
inline int Size::width() {
	return cx;
}
inline int Size::height() {
	return cy;
}

inline Point::Point(int x_, int y_) {
	x = x_;
	y = y_;
}

inline Rect::Rect(RECT r){
	left = r.left;
	right = r.right;
	top = r.top;
	bottom = r.bottom;
}
inline Rect::Rect(int left_, int top_, int right_, int bottom_) {
	left = left_;
	top = top_;
	right = right_;
	bottom = bottom_;
}

inline bool Rect::operator==(Rect& rc) {
	return (rc.left == left) && (rc.right == right) && (rc.top == top) && (rc.bottom == bottom);
}
inline bool Rect::Contains(Point pt) {
	return (pt.x >= left) && (pt.x <= right) && (pt.y >= top) && (pt.y <= bottom);
}
inline bool Rect::Contains(int x, int y) {
	return (x >= left) && (x <= right) && (y >= top) && (y <= bottom);
}
inline bool Rect::Contains(Rect& rc) {
	return (rc.left >= left) && (rc.right <= right) && (rc.top >= top) && (rc.bottom <= bottom);
}
inline bool Rect::Intersects(Rect& other) {
	return (right > other.left) && (left < other.right) && (bottom > other.top) && (top < other.bottom);
}
inline void Rect::Move(int xDelta, int yDelta) {
	left += xDelta;
	top += yDelta;
	right += xDelta;
	bottom += yDelta;
}
inline void Rect::offset(int dx, int dy) {
	Move(dx, dy);
}
inline int Rect::Width() {
	return right - left;
}
inline int Rect::Height() {
	return bottom - top;
}
inline bool Rect::Empty() {
	return (Height() <= 0) || (Width() <= 0);
}

inline void Rect::zoom(int dx, int dy) {
	left -= dx;
	right += dx;
	top -= dy;
	bottom += dy;
}
inline void Rect::zoom(int deltaXY) {
	zoom(deltaXY, deltaXY);
}

inline Rgn::Rgn() :
		rgn(0), owner(false) {
}
inline Rgn::Rgn(HRGN rgn_) :
		rgn(0), owner(false) {
	setRgn(rgn_);
}
inline Rgn::Rgn(Rect r) :
		rgn(0), owner(false) {
	createRectRgn(r);
}
inline Rgn::Rgn(Rect r, int w, int h) :
		rgn(0), owner(false) {
	createRoundRectRgn(r, w, h);
}
inline Rgn::~Rgn() {
	freeRgn();

}

inline void Rgn::setRgn(HRGN rgn_) {
	rgn = rgn_;
	owner = false;
}
inline HRGN Rgn::getRgn() const {
	return rgn;
}

inline Rgn::operator HRGN() {
	return rgn;
}
inline void Rgn::freeRgn() {
	if (owner && rgn) {
		BOOL b = DeleteObject(rgn);
		if (!b) {
			Log << err << "Delete  Rgn Failed! Rgn  maybe in  using!" << endl;
		}
		owner = false;
		rgn = 0;
	}
}
inline void Rgn::manageRgn(HRGN rgn_) {
	freeRgn();
	rgn = rgn_;
	owner = true;
}
inline bool Rgn::needFree() {
	return rgn && owner;
}
inline void Rgn::grab(Rgn& other) {
	rgn = other.rgn;
	owner = other.owner;
	other.rgn = 0;
	other.owner = false;
}
inline HRGN Rgn::discard() {
	HRGN r = rgn;
	rgn = 0;
	owner = 0;
	return r;
}

inline void Rgn::createEmptyRgn() {
	freeRgn();
	rgn = CreateRectRgn(0, 0, 1, 1);
	owner = true;
}
inline void Rgn::createRectRgn(int left, int top, int right, int bottom) {
	freeRgn();
	rgn = CreateRectRgn(left, top, right, bottom);
	owner = true;
}
inline void Rgn::createRectRgn(Rect r) {
	freeRgn();
	rgn = CreateRectRgn(r.left, r.top, r.right, r.bottom);
	owner = true;
}
inline void Rgn::createRoundRectRgn(Rect r, int w, int h) {
	freeRgn();
	rgn = CreateRoundRectRgn(r.left, r.top, r.right, r.bottom, w, h);
	owner = true;
}

inline Rgn& Rgn::OR(const Rgn& other) {
	HRGN dst = CreateRectRgn(0, 0, 1, 1);
	CombineRgn(dst, rgn, other.rgn, RGN_OR);
	manageRgn(dst);
	return *this;
}
inline Rgn& Rgn::DIFF(const Rgn& other) {
	HRGN dst = CreateRectRgn(0, 0, 1, 1);
	CombineRgn(dst, rgn, other.rgn, RGN_DIFF);
	manageRgn(dst);
	return *this;
}
inline Rgn& Rgn::AND(const Rgn& other) {
	HRGN dst = CreateRectRgn(0, 0, 1, 1);
	CombineRgn(dst, rgn, other.rgn, RGN_AND);
	manageRgn(dst);
	return *this;
}

inline BOOL Rgn::Contains(int x, int y) {
	return rgn && PtInRegion(rgn, x, y);
}
inline BOOL Rgn::Contains(Point pt) {
	return rgn && PtInRegion(rgn, pt.x, pt.y);
}

inline Color::Color(UINT32 lcol) {
	co = lcol;
}

inline Color::Color(UINT32 red, UINT32 green, UINT32 blue) {
	Set(red, green, blue);
}
inline Color::Color(UINT32 red, UINT32 green, UINT32 blue, UINT32 alpha) {
	Set(red, green, blue, alpha);
}

inline bool Color::operator==(const Color& other) const {
	return co == other.co;
}

inline Color::operator COLORREF() {
	return co;
}
inline Color& Color::operator =(COLORREF colorref) {
	co = colorref;
	return *this;
}

inline void Color::Set(UINT32 lcol) {
	co = lcol;
}

inline void Color::Set(UINT32 red, UINT32 green, UINT32 blue) {
	co = red | (green << 8) | (blue << 16);
}
inline void Color::Set(UINT32 red, UINT32 green, UINT32 blue, UINT32 alpha) {
	co = red | (green << 8) | (blue << 16) | (alpha << 24);
}
inline UINT32 Color::ValueOfHex(char ch) {
	if (ch >= '0' && ch <= '9') {
		return ch - '0';
	} else if (ch >= 'A' && ch <= 'F') {
		return ch - 'A' + 10;
	} else if (ch >= 'a' && ch <= 'f') {
		return ch - 'a' + 10;
	} else {
		return 0;
	}
}

//TODO support Alpha
inline void Color::SetStr(const char* val) {
	if (*val == '#') {
		val++;
	}
	UINT32 r = ValueOfHex(val[0]) * 16 + ValueOfHex(val[1]);
	UINT32 g = ValueOfHex(val[2]) * 16 + ValueOfHex(val[3]);
	UINT32 b = ValueOfHex(val[4]) * 16 + ValueOfHex(val[5]);
	Set(r, g, b);
}

inline UINT32 Color::AsLong() const {
	return co;
}
inline COLORREF Color::toColorRef() const {
	return co;
}

inline UINT32 Color::GetRed() {
	return co & 0XFF;
}

inline UINT32 Color::GetGreen() {
	return (co >> 8) & 0XFF;
}

inline UINT32 Color::GetBlue() {
	return (co >> 16) & 0XFF;
}
inline UINT32 Color::GetAlpha() {
	return (co >> 24) & 0XFF;
}

inline COLORREF reverseColorRB(COLORREF color) {
	BYTE r = GetRValue(color);
	BYTE g = GetGValue(color);
	BYTE b = GetBValue(color);
	return RGB(b, g, r) ;
}

#endif /* UIUTIL_H_ */
